﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ControlMachine
{
    public class Device
    {
        private string errMsg = "";
        private int runResult = -1;
        private static IntPtr SCARD_PCI_T0;
        private static IntPtr SCARD_PCI_T1;

        private const int SCARD_SUCCESS = 0;


        /// <summary>
        /// 上下文句柄
        /// </summary>
        private int hContext = 0;
        /// <summary>
        /// 卡片句柄
        /// </summary>
        private int hCard = 0;
        /// <summary>
        /// 卡片使用的传输协议
        /// </summary>
        private int activeProtocol = 0;
        /// <summary>
        /// 使用的读卡器名称
        /// </summary>
        private string activeReaderName = "";

        public Device()
        {
            if (SCARD_PCI_T0 == IntPtr.Zero || SCARD_PCI_T1 == IntPtr.Zero)
            {
                IntPtr hWinSCardDll = IntPtr.Zero;
                try
                {
                    hWinSCardDll = PCSCDLL.LoadLibrary("WinSCard.dll");

                    if (hWinSCardDll == IntPtr.Zero)
                    {
                        errMsg = "加载WinsCard.dll失败!";
                       Console.Out.WriteLine(errMsg);
                        throw new Exception(errMsg);
                    }

                    if (SCARD_PCI_T0 == IntPtr.Zero)
                    {
                        SCARD_PCI_T0 = PCSCDLL.GetProcAddress(hWinSCardDll, "g_rgSCardT0Pci");

                        if (SCARD_PCI_T0 == IntPtr.Zero)
                        {
                            errMsg = "获取SCARD_PCI_T0地址失败，请检查WinsCard.dll加载情况!";
                           Console.Out.WriteLine(errMsg);
                            throw new Exception(errMsg);
                        }
                    }

                    if (SCARD_PCI_T1 == IntPtr.Zero)
                    {
                        SCARD_PCI_T1 = PCSCDLL.GetProcAddress(hWinSCardDll, "g_rgSCardT1Pci");

                        if (SCARD_PCI_T1 == IntPtr.Zero)
                        {
                            errMsg = "获取SCARD_PCI_T1地址失败，请检查WinsCard.dll加载情况!";
                            Console.Out.WriteLine(errMsg);
                            throw new Exception(errMsg);
                        }
                    }

                    PCSCDLL.FreeLibrary(hWinSCardDll);
                }
                catch (Exception e)
                {
                    throw new Exception(e.Message);
                }
                finally
                {
                    if (hWinSCardDll != IntPtr.Zero)
                    {
                        PCSCDLL.FreeLibrary(hWinSCardDll);
                    }
                }
            }
        }


        public List<string> iniDevice()
        {
            //获取设备上下文句柄
            runResult = PCSCDLL.SCardEstablishContext(0, 0, 0, out hContext);

            if (runResult != SCARD_SUCCESS)
            {
                errMsg = "获取设备上下文失败，错误代码为：" + runResult.ToString("X");
               Console.Out.WriteLine(errMsg);
                throw new Exception(errMsg);
            }

            if (hContext == 0)
            {
                errMsg = "未能获取设备上下文句柄";
               Console.Out.WriteLine(errMsg);
                throw new Exception(errMsg);
            }
            int mszReaderSize = 0;
            //获取读卡器列表，第一次用于获取字符串长度
            runResult = PCSCDLL.SCardListReaders(hContext, null, null, ref mszReaderSize);

            if (runResult != SCARD_SUCCESS)
            {
                errMsg = "获取读卡器列表，错误代码为：" + runResult.ToString("X");
               Console.Out.WriteLine(errMsg);
                throw new Exception(errMsg);
            }

            List<string> readerList = new List<string>();

            byte[] reads = new byte[mszReaderSize];

            //获取读卡器列表
            runResult = PCSCDLL.SCardListReaders(hContext, null, reads, ref mszReaderSize);

            if (runResult != SCARD_SUCCESS)
            {
                errMsg = "获取读卡器列表，错误代码为：" + runResult.ToString("X");
                Console.Out.WriteLine(errMsg);
                throw new Exception(errMsg);
            }

            ASCIIEncoding encoding = new ASCIIEncoding();
            string strBuffer = encoding.GetString(reads);

            char nullChar = '\0';

            int len = mszReaderSize;
            int index = 0;

            while (strBuffer[0] != nullChar)
            {
                index = strBuffer.IndexOf(nullChar);
                string reader = strBuffer.Substring(0, index);
                len = len - (reader.Length + 1);
                strBuffer = strBuffer.Substring(index + 1, len);
                readerList.Add(reader);
            }

            return readerList;
        }


        public void iniCPUCard(List<string> readerList)
        {
            if (hContext == 0)
            {
                errMsg = "获取设备上下文句柄失败。初始化卡片前需初始化设备！";
                Console.Out.WriteLine(errMsg);
                throw new Exception(errMsg);
            }

            bool isConnectCard = false;

            for (int i = 0; i < readerList.Count; i++)
            {
                string reader = readerList[i];
                runResult = PCSCDLL.SCardConnect(hContext, reader, 1, 1, ref hCard, ref activeProtocol);

                if (runResult != SCARD_SUCCESS)
                {
                    continue;
                }
                else
                {
                    activeReaderName = reader;
                    isConnectCard = true;
                    break;
                }
            }

            if (!isConnectCard)
            {
                errMsg = "未能搜索到卡片！";
               Console.Out.WriteLine(errMsg);
                throw new Exception(errMsg);
            }

            int readerLength = 0;

            int cardStatus = 0;

            int cardProtocal = 0;

            int atrLength = 0;

            runResult = PCSCDLL.SCardStatus(hCard, activeReaderName, ref readerLength
                                            , ref cardStatus, ref cardProtocal, null, ref atrLength);

            if (runResult != SCARD_SUCCESS)
            {
                errMsg = "获取读卡器列表，错误代码为：" + runResult.ToString("X");
               Console.Out.WriteLine(errMsg);
                throw new Exception(errMsg);
            }

            if (cardStatus != 6)
            {
                errMsg = "卡片状态不合法！连接失败！";
               Console.Out.WriteLine(errMsg);
                throw new Exception(errMsg);
            }

            byte[] ATR = new byte[atrLength];

            runResult = PCSCDLL.SCardStatus(hCard, activeReaderName, ref readerLength
                                            , ref cardStatus, ref cardProtocal, ATR, ref atrLength);

            if (runResult != SCARD_SUCCESS)
            {
                errMsg = "获取读卡器列表，错误代码为：" + runResult.ToString("X");
               Console.Out.WriteLine(errMsg);
                throw new Exception(errMsg);
            }

        }


        public byte[] sendAPDU(string sendMessage,byte[] SW12)
        {
            //如果报文是单数，那么就先补全报文
            if (sendMessage.Length % 2 != 0)
            {
                sendMessage = sendMessage + "0";
            }

            byte[] sendMessageBuffer = StringToByteSequence(sendMessage);

            byte[] receiveMessageByte = new byte[512];
            int receiveLength = 521;

            runResult = PCSCDLL.SCardTransmit(hCard
                                            , SCARD_PCI_T0
                                            , sendMessageBuffer
                                            , sendMessageBuffer.Length
                                            , null, receiveMessageByte, ref receiveLength);

            if (runResult != SCARD_SUCCESS)
            {
                errMsg = "获取读卡器列表，错误代码为：" + runResult.ToString("X");
                Console.Out.WriteLine(errMsg);
                throw new Exception(errMsg);
            }

            byte[] retMessage = new byte[receiveLength - 2];

            for (int i = 0; i < receiveLength - 2; i++)
            {
                retMessage[i] = receiveMessageByte[i];
            }

            SW12[0] = receiveMessageByte[receiveLength - 2];
            SW12[1] = receiveMessageByte[receiveLength - 1];

            return retMessage;
        }


        public void closeDevice()
        {
            if (hCard != 0)
            {
                runResult = PCSCDLL.SCardDisconnect(hCard, 1);
            }

            if (hContext != 0)
            {
                runResult = PCSCDLL.SCardReleaseContext(hContext);
            }

        }



        private static byte[] StringToByteSequence(string sourceString)
        {
            int i = 0, n = 0;
            int j = (sourceString.Length) / 2;

            byte[] a = new byte[j];
            for (i = 0, n = 0; n < j; i += 2, n++)
            {
                a[n] = Convert.ToByte(sourceString.Substring(i, 2), 16);
            }
            return a;
        }


    }
}
